/**
 * main.c
 * @date 2020.07.06
 * @author martin
 * @note ftp 服务器1.0版本主函数模块
 */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>

#include "config.h"
#include "ftpServer.h"
#include "common.h"
#include "utils.h"


extern char serv_ip_str[];
extern int ctrl_port;

volatile static int sock_fd = -1;

static void Usage(const char *filename)
{
    fprintf(stderr, "Usage: %s <server ip> <server port>\n", filename);
}

static void sig_func(int sig_no)
{
    /* 调试时，进程捕获信号而终止，关闭监听套接字，避免端口无法释放 */
    if (sig_no == SIGTERM || sig_no == SIGINT) { /* 停止debug 用这2个信号: SIGTERM for IDE Clion, SIGINT for vim  */
        if (sock_fd > 0) {
            puts("server terminated");
            close(sock_fd);
            exit(1);
        }
    }
    else if (sig_no == SIGPIPE) {
        printf("recv signal SIGPIEP\n");
        close(sock_fd);
        exit(1);
    }
}

static void *thread_main(void *arg)
{
    int connfd = (int)arg;

    printf(" ===start new thread %lu === \n", pthread_self());
    printf("begin thread %lu, uid = %d\n", pthread_self(), getuid());

    pthread_detach(pthread_self());

    ftpserver_process(connfd);
    close(connfd);

    printf("begin thread %lu, uid = %d\n", pthread_self(), getuid());
    printf("thread_main with connfd = %d exit\n\n", connfd);
    return NULL;
}

char serv_ip_str[INET_ADDRSTRLEN] = {0};
int ctrl_port;

int main(int argc, char *argv[]) {
    int ctrl_listenfd;


    if (argc == 3) {
        strcpy(serv_ip_str, argv[1]);
        ctrl_port = atoi(argv[2]);
    }
    else {
        if (getlocalipaddr(serv_ip_str) < 0) {
            fprintf(stderr, "getlocalipaddr error\n");
            exit(1);
        }
        ctrl_port = DEFAULT_CTRL_PORT;
    }

    printf("ip = %s, port = %d\n", serv_ip_str, ctrl_port);
    printf("ftp server is starting...\n");

    signal(SIGTERM, sig_func);
    signal(SIGINT, sig_func);
    signal(SIGPIPE, sig_func);

    pr_currentdir_r();

    if (getRootPrivileged() < 0) {
        perror("main getRootPrivileged error");
        exit(1);
    }

    /* 创建套接字监听客户控制连接请求 */
    ctrl_listenfd = socket_create(serv_ip_str, ctrl_port);
    if (ctrl_listenfd < 0) {
        perror("main socket_create error for ctrl");
        exit(1);
    }
    sock_fd = ctrl_listenfd;

    int max_fd = -1;
    fd_set rset, allset;

    FD_ZERO(&allset);
    FD_SET(ctrl_listenfd, &allset); /* 监听集加入控制连接描述符 */
    max_fd = max(ctrl_listenfd, max_fd);
//    FD_SET(data_listenfd, &allset); /* 监听集加入控制数据连接描述符 */
//    max_fd = max(data_listenfd, max_fd);

    while (1) {
        int nready;
        int connfd = 0;
        pthread_t tid;

        rset = allset;

        nready = select(max_fd + 1, &rset, NULL, NULL,  NULL);
        if (nready < 0) {
            if (errno == EINTR) continue;
            perror("select error");
            exit(1);
        }

        if (FD_ISSET(ctrl_listenfd, &rset)) { /* 控制连接请求 */
            connfd = socket_accept(ctrl_listenfd);
            if (connfd < 0) {
                continue;
            }

            pthread_create(&tid, NULL, thread_main, (void *)connfd);
        }
    }
    return 0;
}
